using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Caliburn.Micro;
using MediaOwl.Common;
using MediaOwl.Common.Messages;
using MediaOwl.Common.ScreenManagement;
using MediaOwl.Common.ViewModels;
using MediaOwl.LastFm.Data;
using MediaOwl.LastFm.Model;
using MediaOwl.LastFm.Resources;

namespace MediaOwl.LastFm.ViewModels
{
    [Export, PartCreationPolicy(CreationPolicy.NonShared)]
    public class MusicArtistSingleViewModel : Workitem<LastFmViewModel>
    {
        #region Fields
        private readonly ILastFmDataRepository repository;
        private readonly IEventAggregator eventAggregator;

        #endregion

        #region Constructor

        [ImportingConstructor]
        public MusicArtistSingleViewModel(ILastFmDataRepository repository, IEventAggregator eventAggregator )
        {
            this.repository = repository;
            this.eventAggregator = eventAggregator;
        }

        #endregion

        #region Properties & Backingfields

        private Artist currentArtist;
        public Artist CurrentArtist
        {
            get { return currentArtist; }
            set
            {
                currentArtist = value;
                NotifyOfPropertyChange(() => CurrentArtist);
            }
        }

        public IList<ArtistBase> SimilarArtists
        {
            get { return CurrentArtist == null ? null : CurrentArtist.SimilarArtists; }
        }
        public IList<Album> Albums
        {
            get { return CurrentArtist == null ? null : CurrentArtist.Albums; }
        }
        public IList<Track> Tracks
        {
            get { return CurrentArtist == null ? null : CurrentArtist.Tracks; }
        }
        public IList<Event> NextEvents
        {
            get { return CurrentArtist == null ? null : CurrentArtist.NextEvents; }
        }
        public IList<Tag> Tags
        {
            get { return CurrentArtist == null ? null : CurrentArtist.Tags; }
        }

        #endregion

        #region Methods

        public void WithArtist(ArtistBase artistBase)
        {
            if (artistBase == null)
                return;
            DisplayName = artistBase.Name;
            Run.Coroutine(FetchInfo(artistBase));
        }

        public IEnumerator<IResult> FetchInfo(ArtistBase artistBase)
        {
            yield return Show.Busy(this);

            yield return repository.GetArtist(artistBase, x => CurrentArtist = x, x => eventAggregator.Publish(new ErrorMessage(x)));

            if (CurrentArtist != null)
            {
                yield return repository.GetSimilarArtists(CurrentArtist,
                                                 x => CurrentArtist.SimilarArtists = (IList<ArtistBase>) x,
                                                 x => eventAggregator.Publish(new ErrorMessage(x)));

                yield return repository.GetBiographyOfArtist(CurrentArtist,
                                                             x => CurrentArtist.Bio = x,
                                                             x => eventAggregator.Publish(new ErrorMessage(x)));

                yield return repository.GetTopAlbumsOfArtist(CurrentArtist,
                                                    x => CurrentArtist.Albums = x.OrderByDescending(a => a.PlayCount).ToList(),
                                                    x => eventAggregator.Publish(new ErrorMessage(x)));
                yield return repository.GetTopTracksOfArtist(CurrentArtist,
                                                    x => CurrentArtist.Tracks = x.OrderByDescending(t => t.PlayCount).ToList(),
                                                    x => eventAggregator.Publish(new ErrorMessage(x)));
                yield return repository.GetTopTagsOfArtist(CurrentArtist,
                                                  x => CurrentArtist.Tags = x.ToList(),
                                                  x => eventAggregator.Publish(new ErrorMessage(x)));
                yield return repository.GetNextEventsOfArtist(CurrentArtist,
                                                     x => CurrentArtist.NextEvents = x.ToList(),
                                                     x => eventAggregator.Publish(new ErrorMessage(x)));

                NotifyOfPropertyChange(() => CurrentArtist);
                NotifyOfPropertyChange(() => SimilarArtists);
                NotifyOfPropertyChange(() => Albums);
                NotifyOfPropertyChange(() => Tracks);
                NotifyOfPropertyChange(() => Tags);
                NotifyOfPropertyChange(() => NextEvents);
            }
            yield return Show.NotBusy(this);
        }

        public IEnumerator<IResult> OpenSimilar(object similarArtist)
        {
            if (similarArtist is ArtistBase)
            {
                yield return Show.Child<MusicArtistSingleViewModel>(Helper.GetScreenId((ArtistBase)similarArtist))
                    .In(Parent)
                    .Configured(x => x.WithArtist((ArtistBase) similarArtist));
            }
        }

        public IEnumerator<IResult> OpenPicture()
        {
            yield return Show.Busy(this);
            yield return Show.Child<ShowPictureSingleViewModel>(Helper.GetScreenId(CurrentArtist.PictureLarge))
                .In(Parent)
                .Configured(x => x.WithPicture(CurrentArtist.PictureLarge, string.Format(Captions.PictureTitle, CurrentArtist.Name)));
            yield return Show.NotBusy(this);
        }

        public IEnumerator<IResult> OpenAlbum(object selectedItem)
        {
            if (selectedItem is Album)
            {
                yield return Show.Child<MusicAlbumSingleViewModel>(Helper.GetScreenId((Album)selectedItem))
                    .In(Parent)
                    .Configured(x => x.WithAlbum((Album)selectedItem));
            }
        }

        public IEnumerator<IResult> OpenTrack(object selectedItem)
        {
            if (selectedItem is Track)
            {
                yield return Show.Child<MusicTrackSingleViewModel>(Helper.GetScreenId((Track)selectedItem))
                    .In(Parent)
                    .Configured(x => x.WithTrack((Track)selectedItem));
            }
        }

        public IEnumerator<IResult> OpenTag(object selectedItem)
        {
            if (selectedItem is Tag)
            {
                yield return Show.Child<MusicTagSingleViewModel>(Helper.GetScreenId((Tag)selectedItem))
                    .In(Parent)
                    .Configured(x => x.WithTag((Tag)selectedItem));
            }
        }

        #endregion
    }
}